package com.napenalki.toto.web.controller;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;

import com.napenalki.toto.domain.Event;
import com.napenalki.toto.domain.Match;
import com.napenalki.toto.domain.Prediction;
import com.napenalki.toto.domain.SpecialEvent;
import com.napenalki.toto.domain.Stages;
import com.napenalki.toto.domain.User;
import com.napenalki.toto.service.EventService;
import com.napenalki.toto.service.PredictionService;

@Controller
@RequestMapping(value = "/prediction")
public class PredictionController {

    private EventService eventService;
    private PredictionService predictionService;

    @Autowired
    public PredictionController(PredictionService predictionService,
            EventService eventService) {
        this.eventService = eventService;
        this.predictionService = predictionService;
    }

    @RequestMapping(value = "/match", method = RequestMethod.GET)
    public String getStagePredictions(ModelAndView mav,
            @RequestParam Stages stage) {
        if (stage == null) {
            return "/prediction/invalidstage";
        }

        List<Match> matches = eventService.findMatchesByStage(stage);

        mav.addObject("matches", matches);
        mav.addObject("userPredictions", getUserPredictionsForEvents(matches,
                getCurrentUser()));

        return "/prediction/matches";
    }

    @RequestMapping(value = "/mypredictions", method = RequestMethod.GET)
    public String getPredictionsForCurrentUser(ModelAndView mav) {
        String userName = getCurrentUser();
        List<Prediction> predictions = predictionService
                .findPredictionsByUser(userName);
        mav.addObject("predictions", predictions);
        return "/prediction/mypredictions";
    }

    @RequestMapping(value = "/groupwinners", method = RequestMethod.GET)
    public String getGroupWinnerPredictions(ModelAndView mav) {
        List<SpecialEvent> groupEvents = eventService
                .findAllGroupWinnerSpecialEvents();
        mav.addObject("groupEvents", groupEvents);
        mav.addObject("userPredictions", getUserPredictionsForEvents(
                groupEvents, getCurrentUser()));

        return "prediction/groupwinners";
    }

    @RequestMapping(value = "/special", method = RequestMethod.GET)
    public String getSpecialPredictions(ModelAndView mav) {
        List<SpecialEvent> specialEvents = eventService
                .findAllNonGroupWinnerSpecialEvents();

        mav.addObject("specialEvents", specialEvents);
        mav.addObject("userPredictions", getUserPredictionsForEvents(
                specialEvents, getCurrentUser()));

        return "prediction/special";
    }

    @RequestMapping(value = "/submit", method = RequestMethod.POST)
    public String submitPredictions(ModelAndView mav,
            @ModelAttribute Map<String, Prediction> userPredictions) {
        Iterator<String> keys = userPredictions.keySet().iterator();
        List<String> updated = new ArrayList<String>();

        while (keys.hasNext()) {
            String key = keys.next();
            Prediction pred = userPredictions.get(key);
            if (pred.getPrediction() != null) {
                // Double-check with the DB for locked matches
                Event predictedEvent = pred.getEvent();
                Event dbEvent = null;
                if (predictedEvent instanceof Match)
                {
                    dbEvent = eventService.findMatchById(predictedEvent.getId());
                } else {
                    dbEvent = eventService.findSpecialEvendById(predictedEvent.getId());
                }
                
                if (!dbEvent.isLocked()) {
                    predictionService.updatePrediction(pred);
                    updated.add(key);
                }
            }
        }

        mav.clear();
        mav.addObject("successfulPredictions", updated);

        return "redirect:prediction/success";
    }

    private String getCurrentUser() {
        return (String) SecurityContextHolder.getContext().getAuthentication()
                .getPrincipal();
    }

    private Map<String, Prediction> getUserPredictionsForEvents(
            List<? extends Event> events, String userName) {
        Map<String, Prediction> userPredictions = new HashMap<String, Prediction>();

        for (Event event : events) {
            Prediction pred = predictionService.findPredictionByUserAndEvent(
                    userName, event);
            // Even if prediction is null, add it to the map
            if (pred == null) {
                pred = new Prediction(new User(userName), event, null);
            }
            userPredictions.put(event.toString(), pred);
        }

        return userPredictions;
    }

}
